﻿using System;

using System.Collections.Generic;
using System.Text;
using Silvermoon.Controls;
using System.Diagnostics;

namespace Silvermoon.Core
{
    /// <summary>
    /// Handles time events both for refreshing the graphics and performing asynchronous and synchronous animations/transitions in a synchronized way.
    /// </summary>
    internal class TimeEventServer : IDisposable
    {
        /// <summary>
        /// Specifies in which interval will be refreshed at maximum.
        /// </summary>
        const int MaxTickRefresh = 1000 / 30;
        #region fields

        private System.Windows.Forms.Timer timer;
        private Screen host;
        private TimeEventArgs timeEventArgs;
        private int lastTick;

#if ANALYSIS
        const int tickstacksize = 25;
        int[] ticks = new int[tickstacksize];
        int tickstackptr = 0;
        int ticksum = 0;
        int lasttick;
#endif

        #endregion
        #region IDisposable Members


        public TimeEventServer(Screen host)
            : base()
        {
            this.host = host;
            timeEventArgs = new TimeEventArgs();

            timer = new System.Windows.Forms.Timer();
            timer.Tick += new EventHandler(OnEventTick);
            timer.Interval = 1000 / 30;

        }

        public void Dispose()
        {
            if (timer != null)
            {
                timer.Tick -= OnEventTick;
                timer.Enabled = false;
                timer.Dispose();
                timer = null;
            }
        }

        #endregion
        #region props

#if ANALYSIS
        public float TicksPerFrame { get { return ((float)ticksum) / ((float)tickstacksize); } }
#else
        public float TicksPerFrame {get{return 0;}}
#endif

        public bool Enabled { get { return timer != null ? timer.Enabled : false; } set { timer.Enabled = value; } }

        #endregion
        #region methods

        void OnEventTick(object sender, EventArgs e)
        {
            Progress();
        }

        internal void Progress()
        {
            int tick = Environment.TickCount;
            int dt = tick - lastTick;
            if ((dt) < MaxTickRefresh)
            {
                timer.Interval = MaxTickRefresh - dt;
            }
            else
            {
                PerformAnalysis(tick);
                lastTick = tick;
                if (Tick != null)
                {
                    timeEventArgs.SetTick(tick);
                    Tick(this, timeEventArgs);
                }

                if (!host.IsRendering && Enabled && host.Renderer.Invalidated)
                {
                    timer.Interval = 1;
                    host.Render();
                }
            }
        }

        /// <summary>
        /// Only compiles when ANALYSIS is defined in project properties  under Build/Conditional compilation properties (separated with comma).
        /// </summary>
        [Conditional("ANALYSIS")]
        private void PerformAnalysis(int tick)
        {
#if ANALYSIS
            int dt = tick - lasttick;
            lasttick = tick;

            int tick0 = tickstackptr + 1;
            if (tick0 >= tickstacksize) tick0 = 0;
            ticksum += dt - ticks[tick0];
            ticks[tick0] = dt;
            tickstackptr = tick0;
#endif
        }

        #endregion
        #region events

        public event EventHandler<TimeEventArgs> Tick;

        #endregion
    }

    #region TimeEventArgs

    public class TimeEventArgs : EventArgs
    {
        /// <summary>
        /// Gets the current system tick in milliseconds
        /// </summary>
        public int Tick { get; private set; }

        internal TimeEventArgs()
            : base()
        {
        }

        internal void SetTick(int value)
        {
            Tick = value;
        }
    }

    #endregion
}
